/*
 * ImagesLoader.java
 *
 * Created on November 12, 2006, 11:28 AM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

/**
 * Images Loader takes the name of an images list file, and loads all
 * images from that list.
 *
 *images loaded can be of four different types:
 *o - a single image
 *n - a numbered list of images
 *s - a number of images loaded as a graphics strip - such as a gif with several images in it
 *g - a group of images each with different names
 * @author Owner
 */
package com.dalonedrau.awt.imagesloader;

import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import javax.imageio.ImageIO;
/**
 * Based on the work of Andrew Davison from
 * <u>Killer Game Programming in Java</u>.
 * @author Andrew Davison
 */
public final class ImagesLoader {
	/** 3. */
	private static final int THREE = 3;
	/**the container for all group sets with their individual image names. */
	private HashMap<String, ArrayList<String>> gNamesMap;
	/**
	 * the <code>GraphicsConfiguration</code>
	 * object for the system's monitor.
	 */
	private GraphicsConfiguration graphicsConfig;
	/**
	 * the <code>HashMap</code> containing all
	 * images indexed by their set name.
	 */
	private HashMap<String, ArrayList<BufferedImage>> imagesMap;
	/** the folder containing the image library. */
	private String libraryFolder;
	/** Creates a new instance of <code>ImagesLoader</code>. */
	public ImagesLoader() {
		GraphicsEnvironment ge =
			GraphicsEnvironment.getLocalGraphicsEnvironment();
		// load the graphics configuration
		graphicsConfig = ge.getDefaultScreenDevice().getDefaultConfiguration();
		imagesMap = new HashMap<String, ArrayList<BufferedImage>>();
		gNamesMap = new HashMap<String, ArrayList<String>>();
	}
	/**
	 * Creates a new instance of <code>ImagesLoader</code>.
	 * @param name the name of the image file to load
	 * @param folder the directory containing the image
	 * source files and listing
	 * @throws Exception if there are problems
	 * loading the supplied file
	 */
	public ImagesLoader(final String name, final String folder)
	throws Exception {
		StringBuffer path = new StringBuffer();
		path.append(folder);
		if (folder.startsWith("com")
				&& !folder.endsWith("/")) {
			path.append("/");
		} else if (!folder.startsWith("com")
				&& !folder.endsWith("\\")) {
			path.append("\\");
		}
		libraryFolder = path.toString();
		GraphicsEnvironment ge =
			GraphicsEnvironment.getLocalGraphicsEnvironment();
		// load the graphics configuration
		graphicsConfig = ge.getDefaultScreenDevice().getDefaultConfiguration();
		imagesMap = new HashMap<String, ArrayList<BufferedImage>>();
		gNamesMap = new HashMap<String, ArrayList<String>>();
		try {
			loadImagesFile(name);
		} catch (Exception exception) {
			throw exception;
		} // end try-catch block
	}
	/**
	 * Gets a list of all single images loaded into the image library.
	 * @return ArrayList
	 * @throws Exception if an image listed in the imagesmap is not found
	 */
	public ArrayList<String> getAllSingleImages() throws Exception {
		try {
			ArrayList<String> images = new ArrayList<String>();
			Iterator<String> iter = imagesMap.keySet().iterator();
			while (iter.hasNext()) {
				String key = iter.next();
				if (getNumberOfImages(key) == 1) {
					images.add(key);
				}
			}
			return images;
		} catch (Exception ex) {
			throw ex;
		}
	}
	/**
	 * Processes a line of text and loads the
	 * image file as a blocked number of images.
	 * @param line the line of text to process
	 * @throws Exception if the line of text has an invalid string
	 */
	private void getBlockedImages(final String line) throws Exception {
		final int minValues = 4;
		// b filename xx,yy #
		String[] splitText = null; // String array to hold each line's elements
		splitText = line.split(" "); // split the line by its spacing
		// if there are more than two elements, do not process
		if (splitText.length < minValues) {
			throw new Exception("ImagesLoader getBlockedImages() "
					+ "invalid line: " + line);
		} else {
			loadBlockImage(splitText);
		}
	}
	/**
	 * Processes a line of text and loads the
	 * single image file named in it.
	 * Input should be in this format: o < fnm >
	 * @param line the line of text to process
	 * @throws Exception if the line of text has an invalid string
	 */
	private void getFileNameImage(final String line) throws Exception {
		String[] splitText = null; // String array to hold each line's elements
		splitText = line.split(" "); // split the line by its spacing
		// if there are more than two elements, do not process
		if (splitText.length != 2) {
			throw new Exception("ImagesLoader getFileNameImage() "
					+ "invalid filename: " + line);
		} else {
			loadSingleImage(splitText[1]);
		} // end else there are 2 elements in the line
	}
	/**
	 * Processes a line of text and loads the
	 * image file as a group of images.
	 * @param line the line of text to process
	 * @throws Exception if the line of text has an invalid string
	 */
	private void getGroupImages(final String line) throws Exception {
		final int minValues = ImagesLoader.THREE;
		String[] splitText = null; // String array to hold each line's elements
		splitText = line.split(" "); // split the line by its spacing
		// if there are more than two elements, do not process
		if (splitText.length < minValues) {
			throw new Exception("ImagesLoader getGroupImages() "
					+ "invalid line: " + line);
		} else {
			loadGroupImage(splitText);
		}
	}
	/**
	 * Returns the first image associated with the
	 * image name in the <code>HashMap</code>.
	 * @param name the name of the image
	 * @return <code>BufferedImage</code> the first image in the ArrayList
	 * @throws Exception if name is not a key in the imagesMap
	 */
	public BufferedImage getImage(final String name) throws Exception {
		if (!imagesMap.containsKey(name)) {
			throw new Exception("ImagesLoader Error "
					+ "- imagesMap does not contain key " + name);
		}
		ArrayList<BufferedImage> list = imagesMap.get(name);
		return list.get(0);
	}
	/**
	 * Returns the selected image in an n-type <code>HashMap</code>.
	 * @param name the name of the image
	 * @param position the position of the image in the ArrayList
	 * @return <code>BufferedImage</code> the image stored at the n-position
	 * @throws Exception if name is not a key in the imagesMap
	 */
	public BufferedImage getImage(final String name,
			int position) throws Exception {
		if (!imagesMap.containsKey(name)) {
			throw new Exception("ImagesLoader Error"
					+ "- imagesMap does not contain key " + name);
		}
		ArrayList<BufferedImage> list = imagesMap.get(name);
		// if the given position is out of bounds, return the first image
		if (position < 0 || position >= list.size()) {
			position = 0;
		} // end if
		return list.get(position);
	}
	/**
	 * Returns the selected image in a g-type <code>HashMap</code>.
	 * @param groupName the name of the image group
	 * @param imageName the name for the image frame in the image group
	 * @return <code>BufferedImage</code> the image stored at the
	 * imageName position for group groupName
	 * @throws Exception if groupName is not a key in the gNamesMap
	 */
	public BufferedImage getImage(final String groupName,
			final String imageName) throws Exception {
		if (!gNamesMap.containsKey(groupName)) {
			throw new Exception("ImagesLoader Error - "
					+ "gNamesMap does not contain key " + groupName);
		}
		ArrayList<String> namesList = gNamesMap.get(groupName);
		int index = namesList.indexOf(imageName);
		// if the requested image is not found, return the first image
		if (index == -1) {
			index = 0;
		}
		return getImage(groupName, index);
	}
	/**
	 * Returns the <code>ArrayList</code> containing all images for that name.
	 * @param name the name of the images list
	 * @return <code>ArrayList</code> the <code>ArrayList</code>
	 * contained in the <code>HashMap</code> for that name
	 * @throws Exception if name is not a key in the imagesMap
	 */
	public ArrayList<BufferedImage> getImages(final String name)
	throws Exception {
		if (!imagesMap.containsKey(name)) {
			throw new Exception("ImagesLoader Error - "
					+ "imagesMap does not contain key " + name);
		}
		return imagesMap.get(name);
	}
	/**
	 * Processes a line of text and loads the
	 * image file as a multiple number of images.
	 * @param line the line of text to process
	 * @throws Exception if the line of text has an invalid string
	 */
	private void getMultipleImages(final String line) throws Exception {
		final int minValues = 4;
		String[] splitText = null; // String array to hold each line's elements
		splitText = line.split(" "); // split the line by its spacing
		// if there are more than two elements, do not process
		if (splitText.length < minValues) {
			throw new Exception("ImagesLoader getMultipleImages() "
					+ "invalid line: " + line);
		} else {
			loadMultipleImage(splitText);
		}
	}
	/**
	 * Processes a line of text and loads several
	 * numbered image files stored using the image name.
	 * input should be in this format: n <fnm*.ext> <number>
	 * @param line the line of text to process
	 * @throws Exception if the line of text has an invalid string
	 */
	private void getNumberedImages(final String line) throws Exception {
		String[] splitText = null; // String array to hold each line's elements
		splitText = line.split(" "); // split the line by its spacing
		// if there are more or less than three elements, do not process
		if (splitText.length != ImagesLoader.THREE) {
			throw new Exception("ImagesLoader getNumberedImages() "
					+ "invalid line: " + line);
		} else {
			int count = Integer.parseInt(splitText[2]);
			// the number of files in the numbered image
			// break out the file name.  split the file by
			// the dot into two elements,
			// then capture the images name
			String[] splitSplit = splitText[1].split("\\.");
			String fileName = splitSplit[0].substring(0,
					splitSplit[0].length() - 1);
			String fileExtension = "." + splitSplit[1];
			loadNumberedImage(fileName, fileExtension, count);
		} // end else there are 3 elements in the line
	}
	/**
	 * Returns the number of images stored in the hashmap for a specific group.
	 * @param name the name of the image group
	 * @return int the size of the image list for the group
	 * @throws Exception if name is not a key in the imagesMap
	 */
	public int getNumberOfImages(final String name) throws Exception {
		if (!imagesMap.containsKey(name)) {
			throw new Exception("ImagesLoader Error - "
					+ "imagesMap does not contain key " + name);
		}
		ArrayList<BufferedImage> list = imagesMap.get(name);
		return list.size();
	}
	/**
	 * Takes a String file name, and returns the name of
	 * the file without its extension.  for example, getPrefix( ball.png)
	 * would just return ball.
	 * @param name the file name
	 * @return <code>String</code> the file name without its extension
	 * @throws Exception if there are too many '.'s in the file name
	 */
	private String getPrefix(final String name) throws Exception {
		String[] split = null;
		String prefix = null;
		split = name.split("\\."); // split the name at the literal dot
		// if there are more or less than 2 elements, display an error
		if (split.length != 2) {
			throw new Exception("ImagesLoader getPrefix() "
					+ "invalid file name: " + name);
		}
		// check for /'s
		String[] split2 = split[0].split("/");
		if (split2.length > 0) {
			prefix = split2[split2.length - 1];
		} else {
			prefix = split[0];
		}
		// return the file name without its extension
		return prefix;
	}
	/**
	 * Processes a line of text and loads the
	 * image file as a strip of images.
	 * input should be in this format: s filename number
	 * @param line the line of text to process
	 * @throws Exception if the line of text has an invalid string
	 */
	private void getStripImage(final String line) throws Exception {
		String[] splitText = null; // String array to hold each line's elements
		splitText = line.split(" "); // split the line by its spacing
		// if there are more than two elements, do not process
		if (splitText.length != ImagesLoader.THREE) {
			throw new Exception("ImagesLoader getStripImage() "
					+ "invalid line: " + line);
		} else {
			loadStripImage(splitText[1], Integer.parseInt(splitText[2]));
		} // end else there are 2 elements in the line
	}
	/**
	 * Loads a "block" image file. The images in this file are "blocked"
	 * out in equal dimensions.
	 * @param imageInfo the multiple image information
	 * @return true if the file was successfully loaded; false otherwise
	 * @throws Exception if there was an error during loading
	 */
	private boolean loadBlockImage(final String[] imageInfo)
	throws Exception {
		boolean success = false;
		String imageName = imageInfo[1];
		BufferedImage multi = loadImage(imageName);
		int width = Integer.parseInt(imageInfo[2].split(",")[0]);
		int height = Integer.parseInt(imageInfo[2].split(",")[1]);
		int numImages = Integer.parseInt(imageInfo[ImagesLoader.THREE]);
		ArrayList<BufferedImage> list =
			new ArrayList<BufferedImage>(); // create a new list
		int x = 0, y = 0;
		for (int i = 0; i < numImages; i++) {
			list.add(loadSingleImageFromMultiple(x,  y, width, height, multi));
			x += width;
			if (x >= multi.getWidth()) {
				x = 0;
				y += height;
			}
		}
		imagesMap.put(getPrefix(imageName), list); // put the name and list
		// together in the imagesMap
		success = true;
		return success;
	}
	/**
	 * Loads a single image by name and adds it to
	 * the ImagesLoader hashmap.
	 * @param line the String array containing the
	 * group name and all associated files
	 * @throws Exception if an error occurs during loading
	 * @return boolean indication success or failure
	 */
	public boolean loadGroupImage(final String[] line) throws Exception {
		boolean success = false;
		String imageName = line[1];
		String output = "Loaded group " + imageName + ": ";
		// make sure the image name isnt already in the imagesMap.
		// there cant be two images called 'bouncing ball'
		if (imagesMap.containsKey(imageName)) {
			throw new Exception("ImagesLoader loadGroupImage() "
					+ "imagesMap duplicate image: " + imageName);
		} else if (gNamesMap.containsKey(imageName)) {
			throw new Exception("ImagesLoader loadGroupImage() "
					+ "gNamesMap duplicate group: " + imageName);
		} else {
			// for each image being loaded, it is loaded,
			//two lists are added to the hashmaps
			// the first is a list of images, whose key is the group name.
			// the second is a list of String made up of the
			//file names of each image, key is the group name.
			ArrayList<BufferedImage> imageList =
				new ArrayList<BufferedImage>(); // create a new image list
			ArrayList<String> nameList =
				new ArrayList<String>(); // create a new name list
			for (int i = 2; i < line.length; i++) {
				// call loadImage to create a buffered image
				BufferedImage bufferedImage = loadImage(line[i]);
				// if the BufferedImage was created, add it to the hashmap
				if (bufferedImage != null) {
					imageList.add(bufferedImage); // add this image to the list
					nameList.add(getPrefix(line[i])); // add name to the list
					output += getPrefix(line[i]) + " ";
					success = true;
				} else {
					throw new Exception("ImagesLoader loadGroupImage() "
							+ "image " + line[i] + " was not loaded.");
				}
			} // end for loop
			// if all images and names were added successfully,
			// add boths lists to the hashmaps
			if (success) {
				// put the name and list together in the imagesMap, gNamesMap
				imagesMap.put(imageName, imageList);
				gNamesMap.put(imageName, nameList);
			} // end if success
		} // end else the image name wasn't used before
		return success;
	}
	/**
	 * Creates a <code>BufferedImage</code> based upon the file name provided.
	 * @param name the file name
	 * @return <code>BufferedImage</code> the image loaded by the file name
	 * @throws Exception if there is a problem loading the file
	 */
	private BufferedImage loadImage(final String name) throws Exception {
		BufferedImage image = null, copy = null;
		String filePath = libraryFolder + name;
		try {
			if (libraryFolder.startsWith("com")) { // jar implementation
				InputStream is =
					getClass().getClassLoader().getResourceAsStream(filePath);
				image = ImageIO.read(is);
			} else {
				File file = new File(".\\", filePath);
				if (file.exists()) {
					image = ImageIO.read(file);
				} else {
					throw new Exception("ImagesLoader loadImage() file "
							+ filePath + " did not exist.");
				}
			}
			if (image == null) {
				throw new Exception("ImagesLoader loadImage() "
						+ "cannot load image from " + filePath);
			}
			int transparency = image.getColorModel().getTransparency();
			// create a copy of the BufferedImage
			copy = graphicsConfig.createCompatibleImage(image.getWidth(),
					image.getHeight(), transparency);
			// create a Graphics context
			Graphics2D g2d = copy.createGraphics();
			//copy the image
			g2d.drawImage(image, 0, 0, null); // render the image
			g2d.dispose(); // dispose of the Graphics2D object
		} catch (Exception exception) {
			throw exception;
		} // end try-catch block
		return copy;
	}
	/**
	 * Loads an images file and populate the hashmaps.
	 * @param name the name of the image file to load
	 * @throws Exception if there are
	 * problems loading the supplied file
	 */
	public void loadImagesFile(final String name) throws Exception {
		if (libraryFolder == null) {
			throw new Exception("libraryFolder is null");
		}
		StringBuffer fileName = new StringBuffer();
		fileName.append(libraryFolder);
		fileName.append(name);
		BufferedReader input = null;
		try {
			if (libraryFolder != null
					&& libraryFolder.startsWith("com")) { // jar implementation
				InputStream is =
					getClass().getClassLoader().getResourceAsStream(
							fileName.toString());
				input  = new BufferedReader(new InputStreamReader(is));
			} else { // file implementation
				File file = new File(".\\", fileName.toString());
				// all work is done if the data file exists.
				// otherwise, an error dialog is displayed
				if (file.exists()) {
					input = new BufferedReader(new FileReader(file));
				} else {
					throw new Exception("ImagesLoader loadImagesFile()- "
							+ fileName + " did not exist.");
				}
			}
			String inText = ""; // String object to read
			// in each line of the file
			inText = input.readLine(); // priming read
			// as long as lines are being read from file
			while (inText != null) {
				if (inText.length() != 0
						&& !inText.startsWith("//")) {
					// read the line prefix character and convert to lower case
					char prefix = Character.toLowerCase(inText.charAt(0));
					switch (prefix) {
					case 'o':
						//logger.debug( "o line - " + inText );
						getFileNameImage(inText);
						break;
					case 'n':
						//logger.debug( "n line - " + inText );
						getNumberedImages(inText);
						break;
					case 's':
						//logger.debug( "s line - " + inText );
						getStripImage(inText);
						break;
					case 'g':
						//logger.debug( "g line - " + inText );
						getGroupImages(inText);
						break;
					case 'm':
						//logger.debug( "m line - " + inText );
						getMultipleImages(inText);
						break;
					case 'b':
						//logger.debug( "m line - " + inText );
						getBlockedImages(inText);
						break;
					default:
						throw new Exception("Undefined line marker: "
								+ prefix + " at " + inText);
					}
				}
				inText = input.readLine(); // read next line
			}
			input.close(); // not necessary, but still good practice
		} catch (Exception exception) {
			throw exception;
		}
	}
	/**
	 * Loads a multiple image file.
	 * @param imageInfo the multiple image information
	 * @return true if the file was successfully loaded; false otherwise
	 * @throws Exception if there was an error during loading
	 */
	private boolean loadMultipleImage(final String[] imageInfo)
	throws Exception {
		boolean success = false;
		BufferedImage multi = loadImage(imageInfo[1]);
		for (int i = 2; i < imageInfo.length;) {
			String imageName = imageInfo[i];
			if (imagesMap.containsKey(imageName)) {
				throw new Exception("ImagesLoader loadMultipleImage() "
						+ "imagesMap duplicate image: " + imageName);
			}
			BufferedImage single =
				loadSingleImageFromMultiple(imageInfo[i + 1], multi);
			if (single == null) {
				throw new Exception("ImagesLoader loadMultipleImage() "
						+ "image " + imageName + " was not loaded.");
			}
			ArrayList<BufferedImage> list =
				new ArrayList<BufferedImage>(); // create a new list
			list.add(single); // add this image to the list
			imagesMap.put(imageName, list); // put the name and list
			// together in the imagesMap
			success = true;
			i += 2;
		}
		return success;
	}
	/**
	 * Loads several numbered images by name and adds it to
	 * the ImagesLoader hashmap.  These
	 * images are stored in the hashmap under the same name,
	 * but have a different index in the array list
	 *
	 * @param name the name of the image
	 * @param extension the extenstion of the image file, e.g. .png, .gif, etc..
	 * @param count the number of images to be loaded as a numbered image
	 * @return boolean indication success or failure
	 * @throws Exception if there was an error during loading
	 */
	public boolean loadNumberedImage(final String name, final String extension,
			final int count) throws Exception {
		boolean success = false;
		// make sure the image name isnt already in the imagesMap.
		// there cant be two images called 'bouncing ball'
		if (imagesMap.containsKey(name)) {
			throw new Exception("ImagesLoader loadNumberedImage() "
					+ "imagesMap duplicate image: " + name);
		} else {
			// loop through count number of times to
			// add each image to the array list
			ArrayList<BufferedImage> list =
				new ArrayList<BufferedImage>(); // create a new list
			for (int i = 0; i < count; i++) {
				String imageFile = name + i + extension;
				// call loadImage to create a buffered image
				BufferedImage bufferedImage = loadImage(imageFile);
				// if the BufferedImage was created, add it to the array list
				if (bufferedImage != null) {
					list.add(bufferedImage); // add this image to the list
					success = true;
				} else {
					throw new Exception("ImagesLoader loadNumberedImage() "
							+ "image " + imageFile + " was not loaded.");
				}
			} // end for
			// put the name and list together in the imagesMap
			imagesMap.put(name, list);
		} // end else name wasnt already in imagesMap
		return success;
	}
	/**
	 * Loads a single image by name and adds it to
	 * the <code>ImagesLoader</code> hashmap.
	 * @param name the name of the image
	 * @return boolean indication success or failure
	 * @throws Exception if an image of the same name has
	 * already been loaded
	 */
	public boolean loadSingleImage(final String name) throws Exception {
		boolean success = false;
		String imageName = getPrefix(name);
		// make sure the image name isn't already in the
		// imagesMap.  there cant be two images called
		// 'bouncing ball'
		if (imagesMap.containsKey(imageName)) {
			throw new Exception("ImagesLoader loadSingleImage() "
					+ "imagesMap duplicate image: " + imageName);
		} else {
			// call loadImage to create a buffered image
			BufferedImage bufferedImage = loadImage(name);
			// if the BufferedImage was created, add it to the hashmap
			if (bufferedImage != null) {
				ArrayList<BufferedImage> list =
					new ArrayList<BufferedImage>(); // create a new list
				list.add(bufferedImage); // add this image to the list
				imagesMap.put(imageName, list); // put the name and list
				// together in the imagesMap
				success = true;
			} else {
				throw new Exception("ImagesLoader loadSingleImage() "
						+ "image " + name + " was not loaded.");
			}
		} // end else the image name wasn't used before
		return success;
	}
	/**
	 * Loads a single image from a multi-part image.
	 * @param sx1 the left-most coordinate of the image
	 * @param sy1 the top-most coordinate of the image
	 * @param width the image's width
	 * @param height the image's width
	 * @param multi the multi-part image
	 * @return {@link BufferedImage}
	 * @throws Exception if there is an error with loading
	 */
	private BufferedImage loadSingleImageFromMultiple(final int sx1, 
			final int sy1, final int width, final int height,
			final BufferedImage multi) throws Exception {
		int sx2 = sx1 + width, sy2 = sy1 + height;
		BufferedImage single =
			new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
		Graphics2D g2d = single.createGraphics();
		boolean f = g2d.drawImage(multi, 		// image
				0,								// destination x1
				0,  							// destination y1
				width, 							// destination x2
				height,							// destination y2
				sx1,	// source x1
				sy1, 	// source y1
				sx2,	// source x2
				sy2,	// source y2
				null);
		if (!f) {
			throw new Exception("ImagesLoader loadSingleImageFromMultiple() "
					+ "unable to create image from coordinates: "
					+ sx1 + ", " + sy1);
		}
		g2d.dispose();
		return single;
	}
	/**
	 * Loads a single image from a multi-part image.
	 * @param coordinates the coordinates of the single image
	 * @param multi the multi-part image
	 * @return {@link BufferedImage}
	 * @throws Exception if there is an error with loading
	 */
	private BufferedImage loadSingleImageFromMultiple(final String coordinates,
			final BufferedImage multi) throws Exception {
		String[] values = coordinates.split(",");
		final int len = 4;
		if (values.length != len) {
			throw new Exception("ImagesLoader loadSingleImageFromMultiple() "
					+ "invalid coordinates: " + coordinates);
		}
		int sx1 = Integer.parseInt(values[0]);
		int sy1 = Integer.parseInt(values[1]);
		int width = Integer.parseInt(values[2]);
		int height = Integer.parseInt(values[ImagesLoader.THREE]);
		return this.loadSingleImageFromMultiple(sx1, sy1, width, height, multi);
	}
	/**
	 * Loads a single image by name and add it to
	 * the ImagesLoader hashmap.
	 * @param name the name of the image
	 * @param imageCount the number of images in this animation group
	 * @return boolean indication success or failure
	 * @throws Exception if an error occurs during loading
	 */
	public boolean loadStripImage(final String name,
			final int imageCount) throws Exception {
		boolean success = false;
		String imageName = getPrefix(name);
		// make sure the image name isn't already in the imagesMap.
		//there can't be two images called 'bouncing ball'
		if (imagesMap.containsKey(imageName)) {
			throw new Exception("ImagesLoader loadStripImage() "
					+ "imagesMap duplicate group: "
					+ imageName);
		} else {
			// call loadImage to create a buffered image
			BufferedImage[] bufferedImages =
				loadStripImageArray(name, imageCount);
			// if the BufferedImages was created, add it to the hashmap
			if (bufferedImages != null) {
				ArrayList<BufferedImage> list =
					new ArrayList<BufferedImage>(); // create a new list
				for (int i = 0; i < bufferedImages.length; i++) {
					list.add(bufferedImages[i]); // add each image to the list
				}
				// put the name and list together in the imagesMap
				imagesMap.put(imageName, list);
				success = true;
			} else {
				throw new Exception("ImagesLoader loadStripImage() image for "
						+ name + " was not loaded.");
			}
		} // end else the image name wasn't used before
		return success;
	}
	/**
	 * Loads a strip image, and then "cuts"
	 * the strip into its individual images.
	 * these images are then rendered into an
	 * array of BufferedImages, and then returned.
	 * This assumes the images are loaded in a file like so, evenly spaced:
	 * _______________________________
	 * |         |         |         |
	 * | Image 1 | Image 2 | Image 3 |
	 * |_________|_________|_________|
	 *
	 *@param name the file name
	 *@param number the number of images in the animation set
	 *@return <code>BufferedImage[]</code> an array of BufferedImages
	 * @throws Exception if an error occurs during loading
	 */
	public BufferedImage[] loadStripImageArray(final String name,
			final int number) throws Exception {
		BufferedImage[] imageCells = null;
		// if the caller specified a strip of 0 images, display an error
		if (number <= 0) {
			throw new Exception("ImagesLoader "
					+ "loadStripImageArray() number parameter was 0");
		}
		BufferedImage stripOfImages;
		// if an image using the supplied name can't
		// be loaded, throw an exception
		try {
			stripOfImages = loadImage(name);
		} catch (Exception exception) {
			throw exception;
		} // end try-catch block
		// now that the number and image itself
		// have been validated, begin the "cutting"
		// get the height, width, and transparency of each image cell
		int width = stripOfImages.getWidth() / number;
		int height = stripOfImages.getHeight();
		int transparency = stripOfImages.getTransparency();
		imageCells = new BufferedImage[number];
		Graphics2D g2d;
		// for each cell, go through the original image and "cut" them out,
		// rendering each one into an imageCell
		for (int i = 0; i < number; i++) {
			imageCells[i] =
				graphicsConfig.createCompatibleImage(width,
						height,
						transparency);
			// create the Graphics Context
			g2d = imageCells[i].createGraphics();

			// render each image, "cut" to the right size
			g2d.drawImage(stripOfImages,
					0,
					0,
					width,
					height,
					i * width,
					0,
					(i * width) + width,
					height,
					null);
			g2d.dispose(); // dispose of the Graphics2D object
		} // end for loop to "cut" images out and load them into the array
		return imageCells;
	}
}